#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include "cJSON.h"
#include <errno.h>
#include <termios.h>
#include <errno.h>
#include <stdint.h>
#include <termios.h>
#include <shmem.h>
#include <msg_queue_peer.h>
#include <termios.h>
#include <list.h>
#include <unix_sock.h>

#define DEV_UART "/dev/ttyUSB0"
#define MSG "msg_M0"
#define ENV_LEN sizeof(struct env_info)
#define CONVER_ENV_LEN sizeof(struct conver_env_info)
#define MODULE "unixc_test"

static struct unix_param unix_para;
static struct shm_param para;
struct std_node node;
struct m0_node_list *ForJson(struct m0_node_list *head); //json
void *PthreadWrite(void);
void *PthreadMsgCtl();
struct std_node *shm_addr;              //pthread
struct m0_node_list head;               //内核链表 M0
void GetVal_M0(void);                   //获取val
char *CtrM0(int key, unsigned int val); //向M0发送控制
void serial_init(int fd);

char send_buf[256]; //发
char recv_buf[256]; //收

union val_t //信息连
{
    int b_val;
    int i_val;
    float f_val;
};

struct std_node
{
    int key;
    int type;
    int dev_type;
    union val_t old_val;
    union val_t new_val;
    int ret;
};

struct m0_node
{
    int key;        //唯一键值
    char name[128]; //数据点名称
    int type;       //数据点类型
};

struct m0_node_list
{
    struct m0_node node;
    struct list_head list;
};

/* 
M0数据上报 
head：信息头标示，默认发送"st:"三个字符，可校验数据正确性用
temp[0]：温度整数部分
temp[1]：温度小数部分
hum[0]：湿度的整数部分
hum[1]：湿度的小数部分
*/
struct env_info
{
    uint8_t head[3]; //标识位st:  (保留字段，暂未使用)
    uint8_t type;    //数据类型  (保留字段，暂未使用)
    uint8_t snum;    //房间编号(保留字段，暂未使用)
    uint8_t temp[2]; //温度
    uint8_t hum[2];  //湿度
    uint8_t x;       //三轴信息
    uint8_t y;
    uint8_t z;
    uint32_t ill; //光照
    uint32_t bet; //电池电量
    uint32_t adc; //电位器信息
};

//cJSON
struct m0_node_list *ForJson(struct m0_node_list *head) //内核链表指针
{
    char buf[2000] = {0};

    int fd = open("/home/hq/项目/hq_plat/app/res/node.json", O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }

    read(fd, buf, 2000);
    cJSON *root = NULL;
    cJSON *item = NULL;
    cJSON *arr = NULL;
    cJSON *tem = NULL;
    root = cJSON_Parse(buf);

    if (!root)
    {
        printf("err:%s\n", cJSON_GetErrorPtr());
    }
    struct m0_node_list data[9]; //data数据

    INIT_LIST_HEAD(&(head->list));
    item = cJSON_GetObjectItem(root, "m0");
    arr = cJSON_GetObjectItem(item, "data");

    for (int i = 0; i < cJSON_GetArraySize(arr); i++)
    {
        tem = cJSON_GetArrayItem(arr, i);
        item = cJSON_GetObjectItem(tem, "key");
        data[i].node.key = atoi(cJSON_Print(item));
        printf("------------------>%d\n", data[i].node.key);
        item = cJSON_GetObjectItem(tem, "name");
        strcpy(data[i].node.name, cJSON_Print(item));
        item = cJSON_GetObjectItem(tem, "type");
        data[i].node.type = atoi(cJSON_Print(item));

        list_add(&data[i].list, &head->list);
    }

    root = cJSON_CreateObject();
    item = cJSON_CreateObject();
    struct list_head *pos;
    struct m0_node_list *tmp;

    close(fd);
    return head;
}

//M0
void serial_init_M0()
{
    int fd = open(DEV_UART, O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        exit(-1);
    }
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag |= IGNPAR;
    options.c_cflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_cflag = 0;

    cfsetispeed(&options, B1152000);
    cfsetispeed(&options, B1152000);
    tcsetattr(fd, TCSANOW, &options);
}

//pthread   写到共享内存    ，内核链表初始化
void *PthreadWrite(void)
{
    int ret = -1;
    ret = shm_init(&para, "shm_test", sizeof(node));
    if (ret < 0)
    {
        return -1;
    }
    struct std_node *addr = shm_getaddr(&para);
    if (addr == NULL)
    {
        return -1;
    }

    shm_addr = addr;
    struct list_head *pos;
    struct m0_node_list *tmp;
    int i = 0;

    list_for_each_prev(pos, &(head.list));
    {

        tmp = list_entry(pos, struct m0_node_list, list);
        printf("->key : %d\n", tmp->node.key);
        if (tmp->node.key == i + 1)
        {
            (shm_addr + i)->key = tmp->node.key;
            (shm_addr + i)->type = tmp->node.type;
            i++;
        }
    }
}

//接收上报来的控制信息
void *PthreadMsgCtl()
{
    cJSON *root = NULL;
    cJSON *item = NULL;
    root = cJSON_CreateObject();
    item = cJSON_CreateObject();

    char *s;
    int num;
    unsigned int val;
    char data[256];

    strcpy(send_buf,"1");


    while (1)
    {
        if (unix_client_recv(&unix_para, data, sizeof(data),NULL) < 0)
        {
            perror("recv err");
            return -1;
        }
        else
        {
            root = cJSON_Parse(recv_buf);
            root = cJSON_GetObjectItem(root, "data");
            item = cJSON_GetObjectItem(root, "key");
            num = atoi(cJSON_Print(item));
            if (num == 4 || num == 5 || num == 6)
            {
                item = cJSON_GetObjectItem(root, "val");
                val = atoi(cJSON_Print(item) + 1);
                CtrM0(num, val);

                root = cJSON_CreateObject();
                cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(2));
                cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));
                cJSON_AddItemToObject(root, "msg", cJSON_CreateString("控制成功"));

                strcpy(send_buf, cJSON_Print(root));

                if (unix_client_send(&unix_para, send_buf, sizeof(send_buf)) < 0)
                {
                    printf("unix_client_send error\n");
                    return NULL;
                }
            }
            else
            {
                root = cJSON_CreateObject();
                cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(2));
                cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(1));
                cJSON_AddItemToObject(root, "msg", cJSON_CreateString("无效的控制单元"));

                strcpy(send_buf, cJSON_Print(root));
                if (unix_client_send(&unix_para, send_buf, sizeof(send_buf)) < 0)
                {
                    printf("unix_client_send error\n");
                    return -1;
                }
            }
        }
    }
    pthread_exit(NULL);
}
//开线程，不断读向共享内存写入
void *DoUpdata(void *arg)
{
    GetVal_M0();
}

void *WriteDataToShm(void)
{
    pthread_t tidp;
    pthread_create(&tidp, NULL, DoUpdata, NULL);
    pthread_detach(tidp);
}

//M0
unsigned char LED = 0xA0; //灯首地址

unsigned char ALARM = 0x90; //蜂鸣器首地址

unsigned char FAN = 0x80; //风扇首地址

float temperature; //温度
float humidity;    //湿度
int ill;           //光照
void serial_init(int fd)
{
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;

    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    tcsetattr(fd, TCSANOW, &options);
}
float dota_atof(char unitl)
{
    if (unitl > 100)
    {
        return unitl / 1000.0;
    }
    else if (unitl > 10)
    {
        return unitl / 100.0;
    }
    else
    {
        return unitl / 10.0;
    }
}
float dota_adc(unsigned int ratio)
{
    return ((ratio * 3.3) / 1024);
}

 //获取key参数
void GetVal_M0(void)
{
    int i;
    struct list_head *pos;
    struct m0_node_list *tmp;
    int fd;
    int nbytes = 0;
    struct env_info envinfo;
    while (1)
    {
        if ((fd = open(DEV_UART, O_RDWR)) < 0)
        {
            perror("open uart err\n");
            sleep(1);
        }
        else
            break;
    }

    serial_init(fd);
    while (1)
    {
        for (i = 0; i < 3; i++)
        {
            nbytes = read(fd, &envinfo, ENV_LEN);
            if (nbytes == ENV_LEN)
            {
                if ((shm_addr + i)->type == 2)
                {
                    (shm_addr + i)->old_val.i_val = (shm_addr + i)->new_val.i_val;
                }
                else if ((shm_addr + i)->type == 3)
                {
                    (shm_addr + i)->old_val.f_val = (shm_addr + i)->new_val.f_val;
                }
                list_for_each_prev(pos, &head.list);
                {
                    tmp = list_entry(pos, struct m0_node_list, list);
                    if (tmp->node.key == 1 && i == 0)
                    {
                        if ((shm_addr + i)->type == 2)
                        {
                            (shm_addr + i)->new_val.i_val = envinfo.temp[0] + dota_atof(envinfo.temp[1]);
                        }
                        else if ((shm_addr + i)->type == 3)
                        {
                            (shm_addr + i)->new_val.f_val = envinfo.temp[0] + dota_atof(envinfo.temp[1]);
                        }
                    }
                    if (tmp->node.key == 2 && i == 1)
                    {
                        if ((shm_addr + i)->type == 2)
                        {
                            (shm_addr + i)->new_val.i_val = envinfo.hum[0] + dota_atof(envinfo.hum[1]);
                        }
                        else if ((shm_addr + i)->type == 3)
                        {
                            (shm_addr + i)->new_val.f_val = envinfo.hum[0] + dota_atof(envinfo.hum[1]);
                        }
                    }
                    if (tmp->node.key == 3 && i == 2)
                    {
                        if ((shm_addr + i)->type == 2)
                        {
                            (shm_addr + i)->new_val.i_val = envinfo.ill;
                        }
                        else if ((shm_addr + i)->type == 3)
                        {
                            (shm_addr + i)->new_val.f_val = envinfo.ill;
                        }
                    }
                }
            }
        }
    }
}

//val：1真  0假  风扇0、1、2、3
char *CtrM0(int key, unsigned int val)
{
    int fd;
    if ((fd = open(DEV_UART, O_RDWR)) < 0)
    {
        perror("open uart err\n");
        return -1;
    }
    serial_init(fd);

    unsigned char ctr;

    switch (key)
    {
    case 4:
        ctr = (LED | val);
        printf("%d %x\n", key, ctr);
        write(fd, &ctr, 1);
        break;
    case 5:
        ctr = (ALARM | val);
        printf("%d %x\n", key, ctr);
        write(fd, &ctr, 1);
        break;
    case 6:
        ctr = (FAN | val);
        printf("%d %x\n", key, ctr);
        write(fd, &ctr, 1);
        break;

    default:
        break;
    }
}

int main(int argc, char const *argv[])
{
    unix_init_client(&unix_para, MODULE, "unixs_test");
    ForJson(&head);
    puts("***************\n");
    PthreadWrite();

    pthread_t tid;
    pthread_create(&tid, NULL, PthreadMsgCtl, NULL);
    pthread_detach(tid);
    puts("****************\n");

    WriteDataToShm();
    while (1)
    {
        printf("->1 %d %d %f\n", shm_addr->key, shm_addr->type, shm_addr->new_val.f_val);
        printf("->2 %d %d %f\n", (shm_addr + 1)->key, (shm_addr + 1)->type, (shm_addr + 1)->new_val.f_val);
        printf("->3 %d %d %d\n", (shm_addr + 2)->key, (shm_addr + 2)->type, (shm_addr + 2)->new_val.i_val);
        sleep(1);
    }
    return 0;
}